using System;
using System.Collections.Generic;
using System.Linq;
using Wikey.Extensibility.Enums;
using Wikey.Extensibility.Interfaces;
using Wikey.Transformation.Interfaces;

namespace Wikey.Transformation
{
    public class ExpressionEvaluator : IExpressionEvaluator
    {
        private Queue<Token> Tokens;
        private readonly Queue<IExpressionFunction> Functions;
        private IExpressionParser Parser;

        public ExpressionEvaluator()
        {
            Functions = new Queue<IExpressionFunction>();
        }

        public ExpressionEvaluator(IExpressionParser parser,string content) : this()
        {
            Parser = parser;
            Parser.Parse(content);
            Tokens = Parser.TokenQueue;
        }
        
        public ExpressionEvaluator(Queue<Token> tokens) : this()
        {
            Tokens = tokens;
        }
        
        public List<IExpressionFunction> ParsedFunctions
        {
            get
            {
                return Functions.ToList();
            }
        }

        public Queue<IExpressionFunction> ParsedFunctionQueue
        {
            get { return Functions; }
        }
        
        public IExpressionEvaluator Set( Queue<Token> tokenQueue)
        {
            Tokens = tokenQueue;
            return this;
        }

        public IExpressionEvaluator Run()
        {
            ExpressionFunction function = null;
            ExpressionParameter parameter = null;

            while (Tokens.Count > 0 )
            {
                var current = Tokens.Peek();
                if( current.Type == TokenType.Literal)
                {
                    function = new ExpressionFunction {Value = current.Value, Evaluated = true};
                    Functions.Enqueue(function);
                    Tokens.Dequeue();
                    function = null;
                    continue;
                }

                if (current == Token.LeftBracket)
                {
                    function = new ExpressionFunction();        
                }
                else if (current.Type == TokenType.Command)
                {
                    if (function != null) function.Name = current.Value;
                }
                else if (current == Token.RightBracket)
                {
                    if (function != null)
                    {
                        Functions.Enqueue(function);
                        function = null;
                    }
                }
                else if( current == Token.SemiColumn )
                {
                    // after this the parameters are expected
                }
                else if (current.Type == TokenType.Parameter)
                {
                    parameter = new ExpressionParameter
                                    {
                                        Name = current.Value,
                                        Value=string.Empty //we don't like null Strings!
                                    };
                    if (function != null) function.AddParameter(parameter);
                }
                else if ( current == Token.Equal )
                {
                    // after this the parameter value should be there
                }
                else if (current.Type == TokenType.ParameterValue)
                {
                    if (parameter != null)
                    {
                        parameter.Value = current.Value;
                    }
                }

                Tokens.Dequeue();
            }

            CheckDefaultValueApplicable();

            return this;
        }

        private void CheckDefaultValueApplicable()
        {

            foreach (var queue in Functions)
            {
                if (queue.Parameters.Count == 1
                    && String.IsNullOrEmpty(queue.Parameters[0].Value) )
                {
                    queue.Value = queue.Parameters[0].Name;

                }
            }
        }

        public IExpressionEvaluator AddExpressionFunction(IExpressionFunction function)
        {
            Functions.Enqueue(function);

            return this;
        }
    }



}